 /******************************************************************************
 *                  Shanghai ChipON Micro-Electronic Co.,Ltd                  *
 ******************************************************************************
 *  $File Name$       : lin_master.c                                          *
 *  $Author$          : ChipON AE/FAE Group                                   *
 *  $Data$            : 2021-07-8                                             *
 *  $Hard Version     : KF32A156-MINI-EVB_V1.2                                *
 *  $Description$     : This file provides the relevant configuration of LIN  *
 * 						including:                    						  *
 *                          + Configuration USART LIN mode Initialize    	  *
 *                          + LIN sends data							  	  *
 *                          + Standard checksum                               *
 *                          + Configuration USART Initialize	              *
 ******************************************************************************
 *  Copyright (C) by Shanghai ChipON Micro-Electronic Co.,Ltd                 *
 *  All rights reserved.                                                      *
 *                                                                            *
 *  This software is copyright protected and proprietary to                    *
 *  Shanghai ChipON Micro-Electronic Co.,Ltd.                                 *
 ******************************************************************************
 *  ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~  *
 *                     		REVISON HISTORY                               	  *
 *  ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~  *
 *  Data       Version  Author        Description                             *
 *  ~~~~~~~~~~ ~~~~~~~~ ~~~~~~~~~~~~  ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~  *
 *  2021-07-08 00.02.00 FAE Group     Version 2.0 update                      *
 *                                                                            *
 *                                                                            *
 *****************************************************************************/
#include "system_init.h"

/*******************************************************************************
**                      	Private Functions 		             	      	  **
*******************************************************************************/
static uint8_t GetCheckSumValue(uint8_t PctID, uint8_t *Databuf, uint32_t length);
static uint8_t GetParityValue(uint32_t u32id);

/**
 *  @brief :Use LIN2.0 standard check, calculate the test value of LIN data
 *  @param in :PctID 	Data of protection segment ID
 *			   Databuf	Pointer of the data to be sent
 *			   Length	The length of the data to be sent
 *  @param out :None
 *  @retval :calculate data, the LIN2.0 standard check segment
 */
static uint8_t GetCheckSumValue(uint8_t PctID, uint8_t *Databuf, uint32_t length)
{
	uint16_t check_sum = PctID;
	for (uint8_t i = 0; i < length; i++)
	{
		check_sum += Databuf[i];
		if (check_sum > 0xFF)
		{
			check_sum -= 255;
		}
	}
	return (255 - check_sum);
}

/**
 *  @brief :Use LIN2.0 standard check, calculate protection section data
 *  @param in :u32id Input ID data to be processed
 *  @param out :None
 *  @retval :None
 */
static uint8_t GetParityValue(uint32_t u32id)
{
	uint32_t u32Res = 0, ID[6], p_Bit[2], mask = 0;

	/* Store ID in ID[0:5] */
	for (mask = 0; mask < 6; mask++)
		ID[mask] = (u32id & (1 << mask)) >> mask;
	/* ID6 (p_Bit[0]) is the odd parity of ID0, ID1, ID2, and ID4
		ID7(p_Bit[1]) is the even parity of ID1, ID3, ID4, ID5 */
	p_Bit[0] = (ID[0] + ID[1] + ID[2] + ID[4]) % 2;
	p_Bit[1] = (!((ID[1] + ID[3] + ID[4] + ID[5]) % 2));
	/* Get the ID domain value u32Res 
	(the first 6 bits are ID, and the upper two bits are parity bits) */
	u32Res = u32id + (p_Bit[0] << 6) + (p_Bit[1] << 7);
	/* Return ID filed value */
	return u32Res;
}

/*******************************************************************************
**                     		   Global Functions 		             	      **
*******************************************************************************/
/**
 *  @brief : Configure the LIN send data.
 * 			 - Automatic calculation of protection section ID
 * 			 - Automatically calculate the data of the check section
 * 			 - 1.Send the 'SYNCH BREAK' data
 * 			 - 2.Send the 'ProtectID' data
 * 			 - 3.Send the User data
 * 			 - 4.Send the checksum data 
 *  @param in :USARTx	Pointer to USART memory structure,select USART0_SFR~USART8_SFR
 *			   SlaveID 	receiving the data ID
 *			   Databuf	Pointer of the data to be sent
 *			   Length	The length of the data to be sent
 *  @param out :None
 *  @retval :None
 */
void LIN_Send(USART_SFRmap* USARTx, uint8_t SlaveID, uint8_t* Databuf, uint32_t Length)
{
	/* Calculate the protection data */
	uint8_t ProtectID = GetParityValue(SlaveID);
	/* Calculate the checksum data */
	uint8_t CheckVaule = GetCheckSumValue(ProtectID, Databuf, Length);

	/* Wait for the sender to be empty */
	while(!USART_Get_Transmitter_Empty_Flag(USARTx));
	/* Send interval filed and sync filed */
	USARTx->TBUFR = 0x55;
	USART_Transmit_Data_Enable(USARTx, FALSE); 
	USART_Send_Blank_Enable(USARTx, TRUE);
	USART_Transmit_Data_Enable(USARTx, TRUE);
	while (USART_Get_Transmit_BUFR_Empty_Flag(USARTx));
	while (!USART_Get_Transmit_BUFR_Empty_Flag(USARTx));
	/* Send Protected ID */
	USART_SendData(USARTx, ProtectID);
	/* Send user data */
	for (uint8_t i = 0; i < Length; i++)
	{
		USART_SendData(USARTx, Databuf[i]);
	}
	/* Send checksum data */
	USART_SendData(USARTx, CheckVaule);
}

/**
 *  @brief :LIN initial configuration
 * 			- HFCLK is used by default
 * 			- 9600 baud rate
 * 			- enable receive interrupt default
 *  @param in :None
 *  @param out :None
 *  @retval :None
 */
void USART_LIN_config(USART_SFRmap *USARTx)
{
	USART_InitTypeDef USART_InitStructure;

	/* Reset and enable USARTx */
	USART_Reset(USARTx); 
	/* configure USARTx to LIN mode */
	USART_Struct_Init(&USART_InitStructure);
    USART_InitStructure.m_Mode=USART_MODE_FULLDUPLEXASY;                      
    USART_InitStructure.m_TransferDir=USART_DIRECTION_FULL_DUPLEX;             
    USART_InitStructure.m_WordLength=USART_WORDLENGTH_8B;                     
    USART_InitStructure.m_StopBits=USART_STOPBITS_1;                           
    USART_InitStructure.m_BaudRateBRCKS=USART_CLK_HFCLK;                       
    USART_InitStructure.m_BRAutoDetect=USART_ABRDEN_OFF;
    /** Use 16M clock as an example to list the following baud rates 
	 * 	4800    z:208    x:0    y:0
	 * 	9600    z:104    x:0    y:0
	 * 	19200   z:52     x:0    y:0
	 * 	115200  z:8      x:1    y:13
	*/
	/* Integer part z, get value range is 0 ~ 0xFFFF */
    USART_InitStructure.m_BaudRateInteger=104;
	/* Numerator part x, get value range is 0 ~ 0x0f */
    USART_InitStructure.m_BaudRateNumerator=0;
	/* Denominator part y, get value range is 0 ~ 0x0f */
    USART_InitStructure.m_BaudRateDenominator=0;
	USART_Configuration(USARTx,&USART_InitStructure);
	/* Enable receive interrupt */
	USART_RDR_INT_Enable(USARTx,TRUE);	
	/* Enable LIN moudle */
	USART_RESHD_Enable (USARTx, TRUE);					
	USART_Cmd(USARTx,TRUE);                             	
}
